package recording.encoder;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.Locale;

/**
 * @ProjectName: AndroidFFMpeg
 * @Package: recording.encoder
 * @ClassName: MediaMuxerWrapper
 * @Description: MediaMuxer类的作用：封装编码后的视频流和音频流到mp4容器中
 * @Author: wei.yang
 * @CreateDate: 2021/5/19 14:11
 * @UpdateUser: 更新者：wei.yang
 * @UpdateDate: 2021/5/19 14:11
 * @UpdateRemark: 更新说明：
 * @Version: 1.0
 */
public class MediaMuxerWrapper {
    private static final boolean DEBUG = false;    // TODO set false on release
    private static final String TAG = "MediaMuxerWrapper";
    private static final String DIR_NAME = "AVRecSample";
    private static final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
    private String mOutputPath = null;
    private  MediaMuxer mMediaMuxer = null;
    private int mEncoderCount, mStatredCount;
    private boolean mIsStarted;
    private MediaEncoder mVideoEncoder, mAudioEncoder;


    public MediaMuxerWrapper(String ext) {
        if (TextUtils.isEmpty(ext)) ext = ".mp4";
        try {
            mOutputPath = getCaptureFile(Environment.DIRECTORY_MOVIES, ext).toString();
        } catch (Exception e) {
            Log.e(TAG, "sdcard读写权限未打开" + e.getMessage());
        }


        try {
            mMediaMuxer = new MediaMuxer(mOutputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mEncoderCount = mStatredCount = 0;
        mIsStarted = false;
    }
    public String getOutputPath(){
        return mOutputPath;
    }
    public void prepare(){
        if(mVideoEncoder!=null){
            try {
                mVideoEncoder.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(mAudioEncoder!=null){
            try {
                mAudioEncoder.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public void startRecording(){
        if(mVideoEncoder!=null){
            mVideoEncoder.startRecording();
        }
        if(mAudioEncoder!=null){
            mAudioEncoder.startRecording();
        }
    }

    public void stopRecording(){
        if(mVideoEncoder!=null){
            mVideoEncoder.stopRecording();
        }
        if(mAudioEncoder!=null){
            mAudioEncoder.stopRecording();
        }
    }

    public synchronized boolean isStarted(){
        return mIsStarted;
    }


    void addEncoder(final MediaEncoder encoder){
        if (encoder instanceof MediaVideoEncoder) {
            if (mVideoEncoder != null)
                throw new IllegalArgumentException("Video encoder already added.");
            mVideoEncoder = encoder;
        } else if (encoder instanceof MediaAudioEncoder) {
            if (mAudioEncoder != null)
                throw new IllegalArgumentException("Video encoder already added.");
            mAudioEncoder = encoder;
        } else
            throw new IllegalArgumentException("unsupported encoder");
        mEncoderCount = (mVideoEncoder != null ? 1 : 0) + (mAudioEncoder != null ? 1 : 0);
    }
    synchronized boolean start() {
        if (DEBUG) Log.v(TAG,  "start:");
        mStatredCount++;
        if ((mEncoderCount > 0) && (mStatredCount == mEncoderCount)) {
            mMediaMuxer.start();
            mIsStarted = true;
            notifyAll();
            if (DEBUG) Log.v(TAG,  "MediaMuxer started:");
        }
        return mIsStarted;
    }
    synchronized void stop() {
        if (DEBUG) Log.v(TAG,  "stop:mStatredCount=" + mStatredCount);
        mStatredCount--;
        if ((mEncoderCount > 0) && (mStatredCount <= 0)) {
            mMediaMuxer.stop();
            mMediaMuxer.release();
            mIsStarted = false;
            if (DEBUG) Log.v(TAG,  "MediaMuxer stopped:");
        }
    }
    synchronized int addTrack(final MediaFormat format) {
        if (mIsStarted)
            throw new IllegalStateException("muxer already started");
        final int trackIx = mMediaMuxer.addTrack(format);
        if (DEBUG) Log.i(TAG, "addTrack:trackNum=" + mEncoderCount + ",trackIx=" + trackIx + ",format=" + format);
        return trackIx;
    }
    synchronized void writeSampleData(final int trackIndex, final ByteBuffer byteBuf, final MediaCodec.BufferInfo bufferInfo) {
        if (mStatredCount > 0)
            mMediaMuxer.writeSampleData(trackIndex, byteBuf, bufferInfo);
    }
    public static final File getCaptureFile(final String type, final String ext) {
        final File dir = new File(Environment.getExternalStoragePublicDirectory(type), DIR_NAME);
        Log.d(TAG, "path=" + dir.toString());
        dir.mkdirs();
        if (dir.canWrite()) {
            return new File(dir, getDateTimeString() + ext);
        }
        return null;
    }

    private static final String getDateTimeString() {
        final GregorianCalendar now = new GregorianCalendar();
        return mDateFormat.format(now.getTime());
    }
}
